/** Database */
package server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import domain.admin.Admin;
import domain.appointment.Appointment;
import domain.doctor.Doctor;
import domain.exception.ValidationException;
import domain.nurse.Nurse;
import domain.patient.Patient;
import domain.records.DoctorsOrders;
import domain.records.MedicalService;
import domain.records.TreatmentRecord;
import domain.user.User;


/**
 * Temporary Database
 * @author jessienewman
 * @version $Revision: 1.0 $
 */
public class Database {
	
	/**
	 * Field DATABASE.
	 */
	public static final Database DATABASE = new Database();

	/**
	 * Field LOGGER.
	 */
	private static final Logger LOGGER = Logger.getLogger(Database.class.getName());

	//	public List<Patient> patients;
	/**
	 * Field users.
	 */
	public List<User> users;

	//	public List<Nurse> nurses;
	//	public List<Doctor> doctors;
	//	public List<Admin> admins;
	/**
	 * Field appointments.
	 */
	public List<Appointment> appointments;

	//	public List<DoctorsOrders> doctorsOrders;
	//	public Object[][] servicesDO;
	/**
	 * Field services.
	 */
	public List<MedicalService> services;

	/**
	 * Field nextInt.
	 */
	public static int NEXTINT = 0;

	/**
	 * Constructor for Database.
	 */
	public Database() {
		try {
			loadUsersAppointments();
			NEXTINT = users.size() + appointments.size();
		} catch(Exception e) {
			//LOGGER.warning("Created new database." + e.getMessage());
			String pass = "";

			try { 
				byte[] passByte = "pass".getBytes("ASCII");
				MessageDigest digest = MessageDigest.getInstance("SHA-256");
				digest.update(passByte);
				pass = new String(digest.digest(), "ASCII"); 
			} catch (UnsupportedEncodingException ue) {
				ue.printStackTrace(); 
			} catch (NoSuchAlgorithmException ne) {
				ne.printStackTrace();
			}

			users = new ArrayList<User>();
			Nurse n1 = new Nurse("Jennifer", "Kate", "Brady");
			addUser(n1, "Jennifer.Brady", pass);
			Nurse n2 = new Nurse("Alice", "", "Thompson");
			addUser(n2, "Alice.Thompson", pass);
			Nurse n3 = new Nurse("Eric", "Kate", "Smith"); 
			addUser(n3, "Eric.Smith", pass);

			Patient p1 = new Patient("Bill", "Smith", "Andrew", 
					"Bill@gatech.edu", "123 Elm St. Atlanta, GA 30042", 
					makeDate(2, 3, 1991), "Alfa", "pollen"); // $codepro.audit.disable numericLiterals
			addUser(p1, "Bill.Smith", pass);
			Patient p2 = new Patient("Julia", "Perez", "Alex", 
					"Julia@gatech.edu", "546 Wickerton Place Suwanee, GA 40322", 
					makeDate(3, 4, 1990), "State Farm", "dust"); // $codepro.audit.disable numericLiterals
			addUser(p2, "Julia.Perez", pass);
			Patient p3 = new Patient("Ben", "Albert", "Jessie", 
					"Albert@gatech.edu", "324 Cherry Pine Street Anchorage, AL 41411", 
					makeDate(2, 4, 1980), "Blue Cross", "gingers"); // $codepro.audit.disable numericLiterals
			addUser(p3, "Ben.Albert", pass);

			Doctor d1 = new Doctor("Alex", "Matthew", "Peters"); 
			addUser(d1, "Alex.Peters", pass);
			Doctor d2 = new Doctor("Karen", "Allie", "Thompson");
			addUser(d2, "Karen.Thompson", pass);
			Doctor d3 = new Doctor("Ben", "Peter", "Martin");
			addUser(d3, "Ben.Martin", pass);

			Admin a1 = new Admin("Default", "", "Admin");
			addUser(a1, "Admin", pass);

			appointments = new ArrayList<Appointment>();
			DoctorsOrders dos1 = new DoctorsOrders(d3, p2, 
					"Take medicine twice daily", null, "Adderall");
			int height = 52; // $codepro.audit.disable numericLiterals
			int weight = 104; // $codepro.audit.disable numericLiterals
			int temp = 97; // $codepro.audit.disable numericLiterals
			int bp = 20; // $codepro.audit.disable numericLiterals
			int pulse = 40; // $codepro.audit.disable numericLiterals
			TreatmentRecord tr1 = new TreatmentRecord(
					n2, "rash", height, weight, temp, bp, pulse, 
					"Sick with something", dos1);

			Appointment ap1 = new Appointment(d3, p2, makeDate(3, 34, 2011), tr1); // $codepro.audit.disable numericLiterals
			addAppointment(ap1);
		}

		services = new ArrayList<MedicalService>();
		MedicalService s1 = new MedicalService(10, "Blood Work", 400); // $codepro.audit.disable numericLiterals
		services.add(s1);
		MedicalService s2 = new MedicalService(20, "Shot", 30); // $codepro.audit.disable numericLiterals
		services.add(s2);

	}

	/**
	 * Method makeDate.
	 * @param month int
	 * @param day int
	 * @param year int

	 * @return Date */
	private static Date makeDate(int month, int day, int year) {
		Calendar cal = Calendar.getInstance();
		cal.set(year, month, day);
		return cal.getTime();
	}

	/**
	 * Method addAppointment.
	 * @param a Appointment
	 */
	public void addAppointment(Appointment a) {
		a.setAppointmentId(NEXTINT);
		a.getTreatmentRecord().setId(NEXTINT);
		a.getTreatmentRecord().getOrders().setId(NEXTINT);
		appointments.add(a);
		saveAppointments();
	}

	/**
	 * Method addUser.
	 * @param u User
	 * @param userName String
	 * @param password String

	 * @return Integer */
	public Integer addUser(User u, String userName, String password) {
		u.setUsername(userName);
		u.setPassword(password);
		u.setUserId(NEXTINT);
		NEXTINT++; // $codepro.audit.disable assignmentToNonFinalStatic
		//patients.add(p);
		users.add(u);
		saveUsers();
		return NEXTINT - 1;
	}

	/**
	 * super's toString

	 * @return super's toString */
	public String toString() {
		return super.toString();
	}

	/**
	 * Method saveAppointments.
	 */
	public void saveAppointments() {
		File apptFile = new File("appointments.txt");
		FileOutputStream fosAppt = null;
		ObjectOutputStream outAppt = null;
		try {
			fosAppt = new FileOutputStream(apptFile);
			outAppt = new ObjectOutputStream(fosAppt);
		} catch (FileNotFoundException fnfe) {
			LOGGER.warning("File not Found" + fnfe);
		} catch (IOException ioe) {
			LOGGER.warning("IO Exception" + ioe);
		}

		try {
			outAppt.writeObject(appointments);
			outAppt.close();
		} catch (IOException ioe) {
			LOGGER.warning("IO Exception" + ioe);
		}
	}

	/**
	 * Method saveUsers.
	 */
	public void saveUsers() {
		File userFile = new File("users.txt");
		FileOutputStream fosUser = null;
		ObjectOutputStream outUser = null;
		try {
			fosUser = new FileOutputStream(userFile);
			outUser = new ObjectOutputStream(fosUser);
		} catch (FileNotFoundException fnfe) {
			LOGGER.warning("File not Found" + fnfe);
		} catch (IOException ioe) {
			LOGGER.warning("IO Exception" + ioe);
		}

		try {
			outUser.writeObject(users);
			outUser.close();
		} catch (IOException ioe) {
			LOGGER.warning("IO Exception" + ioe);
		}
	}

	/**
	 * Method loadUsersAppointments.
	 * @throws FileNotFoundException
	 * @throws IOException
	 * @throws ClassNotFoundException
	 * @throws ValidationException
	 */
	public void loadUsersAppointments() throws FileNotFoundException,  // $codepro.audit.disable unnecessaryExceptions
	IOException, ClassNotFoundException, ValidationException{
		try {
			FileInputStream fisUsers = new FileInputStream("users.txt");
			FileInputStream fisAppts = new FileInputStream("appointments.txt");
			ObjectInputStream oisUsers = new ObjectInputStream(fisUsers);
			ObjectInputStream oisAppts = new ObjectInputStream(fisAppts);
			users = (ArrayList<User>) oisUsers.readObject();
			appointments = (ArrayList<Appointment>) oisAppts.readObject();
			if (users.isEmpty()) {
				throw new ValidationException("Empty List");
			}
		} catch (FileNotFoundException fnfe) {
			LOGGER.warning("File not Found");
			throw(fnfe);
		} catch (IOException ioe) {
			LOGGER.warning("IO Exception");
			throw(ioe);
		} catch (ClassNotFoundException cnfe) {
			LOGGER.warning("Class not found Exception");
			throw(cnfe);
		} catch (ValidationException ve) {
			throw(ve);
		}
	}
}
